#include "outline/outline.h"
#include "outline/decrease_mask_freedom.h"
#include "outline/grand_poly_bezier_builder2.h"
#include "outline/fast_bspline_adjust.h"
#include <imglib/bitmap.h>

namespace outline {

void trace1(img::bitmap const & bmp, outline_us & polyline)
{
	outlines_us AllOutlines;
	trace(bmp, AllOutlines, true);
	if (AllOutlines.empty())
		throw std::runtime_error("The bitmap contains no outlines");

	//select the longest polyline
	uint idx = 0;
	uint len = AllOutlines[0].size();
	for (uint i = 1; i < AllOutlines.size(); ++i) {
		uint l = AllOutlines[i].size();
		if (len < l) {
			idx = i;
			len = l;
		}
	}
	polyline = AllOutlines[idx];
	assert(outline::closed(polyline));

	//for (unsigned i = 0; i < AllOutlines.size(); ++i) {
	//	if (outline::closed(AllOutlines[i])) {
	//		polyline = AllOutlines[i];
	//		break;
	//	}
	//}
	//if (i == AllOutlines.size())
	//	throw std::runtime_error("The bitmap contains no CLOSED outline");
}

template <typename R>
void decrease_mask_freedom(
	img::bitmap & bmp,
	uint n,
	bool smooth_contour,
	guide_params<R> const & params,
	controls<R> & ctrls,
	std::vector< point<R> > const * attractors,
	std::vector<R> const * tractions
)
{
	assert (n > 0);
	outline_us polyline;
	trace1(bmp, polyline);

	if (ctrls.empty()) {
		grand_params<R> gparams;
		gparams.sharpness_penalty = smooth_contour ? 1 : 0;
		gparams.low = false;
		gparams.hi_max_iterations = params.max_iterations;
		gparams.hi_stop_mean_discrepancy = params.stop_mean_discrepancy;
		gparams.hi_oversample_factor = params.oversample_factor;
		gparams.min_junctions = gparams.max_junctions = n;
		gparams.penalty_for_each_junction = 0;

		grand_poly_bezier_builder2<unsigned short, R> builder;
		builder.set_params(gparams);
		builder.reset(polyline);

		builder.collect_best(&ctrls, 0, attractors, tractions);
	}
	else {
		std::vector<junc_type> junc(ctrls.pieces());
		for (uint i = 0; i < junc.size(); ++i)
			junc[i] = smooth_contour ? junc_smooth_affine : junc_cusp;

		fast_bspline_adjust(
			polyline, 
			fast_bspline_adjust_params(
				params.max_iterations, 
				1 / params.oversample_factor, 
				fit_global_then_local,
				affine, 
				true, //antiloop
				params.search_half_window),
			ctrls, junc,
			(std::vector< point<R> >*)0, (std::vector< point<R> >*)0,
			attractors, tractions
		);
	}

	render(ctrls, bmp);
}

#define INSTANTIATE(R) \
template \
void decrease_mask_freedom( \
	img::bitmap & bmp, \
	uint n, \
	bool smooth_contour, \
	guide_params<R> const & params, \
	controls<R> & ctrls, \
	std::vector< point<R> > const * attractors, \
	std::vector<R> const * tractions \
);

INSTANTIATE(float)
INSTANTIATE(double)

} //namespace outline
